/**
 * ReporterServicesImpl.java
 * 2008-3-13
 * 作者 Administrator
 */
package org.jackysoft.service.impl;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Query;
import org.hibernate.Session;
import org.jackysoft.entity.Department;
import org.jackysoft.entity.Product;
import org.jackysoft.entity.ProductFresh;
import org.jackysoft.entity.ProductQuota;
import org.jackysoft.entity.ProductType;
import org.jackysoft.entity.User;
import org.jackysoft.google.collection.ZTreeNode;
import org.jackysoft.query.QueryField;
import org.jackysoft.report.BadProduct;
import org.jackysoft.report.data.ProductDataExportor;
import org.jackysoft.report.data.ProductDataImporter;
import org.jackysoft.report.google.function.ProductQuotasZTreeFunction;
import org.jackysoft.report.google.function.ProductZtreeFunction;
import org.jackysoft.report.rows.UpdatePriceWork;
import org.jackysoft.service.AbstractStringIdServiceImpl;
import org.jackysoft.service.DepartmentService;
import org.jackysoft.service.ProductService;
import org.jackysoft.service.TechnicsService;
import org.jackysoft.util.Page;
import org.jackysoft.util.SpringSecurityUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;

@Service
@Transactional
public class ProductServiceImpl extends AbstractStringIdServiceImpl<Product>
		implements ProductService {

	/**
	 * 
	 */

	private static final long serialVersionUID = -3227426084160952929L;
	private TechnicsService techService;
    private DepartmentService deptService;
	public ProductServiceImpl() {
		this.type = Product.class;
	}

	@Override
	@Transactional(readOnly=true)
	public Product get(String id) throws DataAccessException {
		if(StringUtils.isEmpty(id))return null;
		Product bean = super.get(id);
		if(bean==null) return null;
		bean.setTechnics(techService.getsByProduct(bean));
		return bean;
	}
	
	@Override
	@Transactional(readOnly=true)
	public Product getPrue(String id) throws DataAccessException {
		if(StringUtils.isEmpty(id))return null;
		Product bean = super.get(id);
		if(bean==null) return null;		
		return bean;
	}
	
	@Override
	public Product getPureofName(String name) throws DataAccessException {
		String hql = HQL("from %s where name='%s'",table(),name);
		Iterator itr = query(hql).iterate();
		return (Product) (itr.hasNext()?itr.next():null);
	}

	@Override
	public void create(Product pdt) throws DataAccessException {
		super.create(pdt);
	}

	@Override
	public Collection<Product> gets(Department department)
			throws DataAccessException {
		if (department == null)
			return Lists.newArrayList();
		Session sess = this.getSession();
		Collection<Department> depts = Lists.newArrayList();
		depts.add(department);
		String hql = "select distinct new Product(p.code,p.name) from "
				+ this.table()
				+ " p join p.providers pvds where pvds in (:pvd)";
		Query q = sess.createQuery(hql).setParameterList("pvd", depts);
		return q.list();
	}

	@Override
	public Collection<Product> getsTyped(ProductType itemType)
			throws DataAccessException {
		String hql = "from " + this.table()
				+ " p  where  p.itemType=:pType";
		List list = getSession().createQuery(hql)
				.setParameter("pType", itemType).list();
		return list;
	}

	@Override
	public boolean ofDepartment(Department dept, Product pdtId) {
		Collection<Department> depts = Lists.newArrayList();
		depts.add(dept);
		String hql = "select count(distinct p.code) from "
				+ this.table()
				+ " p join p.providers depts where p.code=:pid and depts in (:pvds)";
		Object obj = getSession().createQuery(hql)
				.setString("pid", pdtId.getCode())
				.setParameterList("pvds", depts).uniqueResult();
		Long l = Long.parseLong(obj.toString());
		return l == 0L;
	}

	@Override
	public Collection<Department> providers(Product product) {
		Session sess = getSession();
		Product pdt = (Product) sess.get(Product.class, product.getCode());
		return pdt.getProviders();
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public Collection<ProductQuota> getsQuotas(Product pdt)
			throws DataAccessException {
		String hql = "from " + ProductQuota.class.getName()
				+ " q where q.host.code=:pdt";
		List list = getSession().createQuery(hql)
				.setParameter("pdt", pdt.getCode()).list();
		return list;
	}

	@Override
	public void createQuota(Collection<ProductQuota> quotas)
			throws DataAccessException {
		Session sess = getSession();
		Iterator<ProductQuota> itr = quotas.iterator();
		while (itr.hasNext()) {
			ProductQuota b = itr.next();

			sess.save(b);
			sess.flush();
			sess.clear();

		}

	}

	@Override
	public void updateQuota(Collection<ProductQuota> quotas)
			throws DataAccessException {
		Session sess = getSession();
		Iterator<ProductQuota> itr = quotas.iterator();
		while (itr.hasNext()) {
			ProductQuota b = itr.next();
			sess.update(b);

		}
		sess.flush();
		sess.clear();

	}

	@Override
	public Collection<Product> getsTyped(ProductType itemType, Department dept)
			throws DataAccessException {
		Collection<Department> deptslist = new ArrayList<Department>();
		deptslist.add(dept);
		String hql = String
				.format("select distinct new Product(p.code,p.name) from %s p join p.providers provs  where p.itemType=:itype  and provs in (:depts) order by p.code asc",
						table());
		Query q = query(hql).setParameter("itype", itemType).setParameterList(
				"depts", deptslist);
		List list = q.list();
		return list;
	}

	@Override
	public void cleanAllQuota() throws DataAccessException {

		List qlist = getSession().createCriteria(ProductQuota.class).list();
		removeQuota(qlist);

	}

	@Override
	public Collection<Product> getsTypedOfGrouped(ProductType itemType)
			throws DataAccessException {
		User user = SpringSecurityUtils.getCurrentUser();
		Department dept = user.getDepartment();
		return gets(dept);
	}

	@Override
	public Collection<Product> search(String code) throws DataAccessException {
		String hql = "select new Product(p.code,p.name) from "
				+ this.table() + " p  where p.code like '%" + code
				+ "%' order by p.code desc";
		List list = getSession().createQuery(hql).list();
		return list;
	}

	@Override
	public Collection<Product> search(String code, Department dept)
			throws DataAccessException {
		if (dept == null)
			return search(code);
		String hql = "select distinct new Product(p.code,p.name,p.price,p.priceUnit) from "
				+ table()
				+ " p join p.providers pvod where pvod in (:pvod) and  p.code like '%"
				+ code + "%'";
		Collection<Department> depts = Lists.newArrayList();
		depts.add(dept);
		List list = getSession().createQuery(hql)
				.setParameterList("pvod", depts).list();
		return list;
	}

	@Override
	public Collection<ProductQuota> getsQuotas(String code)
			throws DataAccessException {
		Collection<ProductQuota> pqs = Lists.newArrayList();
		String hql = String.format(" from %s q where q.host.code='%s'",
				ProductQuota.class.getName(), code);
		List list = query(hql).list();
		pqs.addAll(list);
		return pqs;
	}

	@Override
	public void removeQuota(Collection<ProductQuota> quotas)
			throws DataAccessException {
		Iterator<ProductQuota> itr = quotas.iterator();
		int count = 0;
		while (itr.hasNext()) {

			Object o = itr.next();
			getSession().delete(o);
			if ((count++) % 20 == 0) {
				getSession().flush();
				getSession().clear();
			}
		}

	}

	@Resource
	public void setDeptService(DepartmentService deptService) {
         this.deptService = deptService;
	}

	@Override
	public ProductQuota calculateQuota(Product parent, Product child)
			throws DataAccessException {
		String hql = String.format(
				"from %s q where q.host=:parent and q.owner=:child",
				ProductQuota.class.getName());
		Iterator itr = getSession().createQuery(hql)
				.setParameter("parent", parent).setParameter("child", child)
				.iterate();
		return (ProductQuota) (itr.hasNext() ? itr.next() : null);
	}

	@Override
	public Collection<ZTreeNode> getProductTree(String parentId,
			Department dept, ProductType itemType) throws DataAccessException {
		Assert.notNull(parentId, "产品编码 " + parentId + " 不是有效的产品编码 ");
		if ("root".equals(parentId)) {
			return Collections2.transform(getsTyped(itemType, dept),
					new ProductZtreeFunction(this));
		}
		return Collections2.transform(getsQuotas(parentId),
				new ProductQuotasZTreeFunction(this));
	}

	@Override
	public void createSingleQuota(ProductQuota quota)
			throws DataAccessException {
		getSession().save(quota);

	}

	@Override
	public void updateSingleQuota(ProductQuota quota)
			throws DataAccessException {
		getSession().update(quota);

	}

	@SuppressWarnings("unchecked")
	@Override
	public Collection<BadProduct> badCodes() throws DataAccessException {
		String hql = String
				.format("select new org.jackysoft.report.BadProduct(code,count(code)) from %s group by code having count(code)>1",
						table());
		List tlist = query(hql).list();
		return tlist;

	}

	@Override
	public Collection<Product> searchbad(String code)
			throws DataAccessException {
		String hql = String.format(" from %s p where p.code='%s'", table(),
				code);
		return query(hql).list();
	}

	public TechnicsService getTechService() {
		return techService;
	}

	@Resource
	public void setTechService(TechnicsService techService) {
		this.techService = techService;
	}

	@Override
	public List<String> importProducts(InputStream stream, String fileName)
			throws DataAccessException {
		String deptName = fileName.substring(0, fileName.lastIndexOf('.'));
		
		return new ProductDataImporter(this, techService,deptService).fromStream(stream, deptName);

	}	

	@Override
	public int getQuotaCount(String code) throws DataAccessException {
		String hql = String.format(
				"select count(*) from %s q where q.host.code=:parent",
				ProductQuota.class.getName());
		Object len = query(hql).setString("parent", code).uniqueResult();
		return Integer.parseInt(len.toString());
	}

	@Override
	public byte[] exportProducts() throws Exception {

		return new ProductDataExportor(this).toExcel();
	}

	@Override
	public Collection<ProductFresh> getFreshs() throws DataAccessException {
		String hql = "from ProductFresh";

		return query(hql).list();
	}
	
	
	

	@Override
	public Page query(org.jackysoft.query.Query qc, Integer pindex, Integer rows)
			throws DataAccessException {
		if(qc==null){
			return this.getsPage(pindex, rows);
		}
		QueryField qf = qc.getFields().get(0);
		String deptId = qf.getValue();
		Department dept = new Department(deptId);
		return gets(pindex,rows,dept);
	}

	@Override
	public Page gets(Integer pindex, Integer offset, Department department)
			throws DataAccessException {

		String hql = String
				.format("select count(distinct  p.code) from %s p join p.providers depts where depts in (:depts)",
						table());
		Collection<Department> depts = Lists.newArrayList();
		depts.add(department);
		Object obj = query(hql).setParameterList("depts", depts).iterate()
				.next();
		Integer count = Integer.parseInt(obj.toString());

		hql = String
				.format("select distinct new Product(p.code,p.name,p.price,p.priceUnit) from %s p join p.providers depts where depts in (:depts) order by p.code desc",
						table());
		int start = pindex * offset;
		if (start < 0)
			start = 0;
		List<Product> list = query(hql).setParameterList("depts", depts)
				.setFirstResult(start).setMaxResults(offset).list();
		Page page = new Page();
		page.setPage(pindex);
		page.setOffset(offset);
		page.setRecords(count);
		page.setRows(list);
		return page;
	}

	@Override
	public void updatePrice(File file) throws DataAccessException {
		priceWork.setSource(file);
		getSession().doWork(priceWork);
	}
	
	
	@Resource
	public void setPriceWork(UpdatePriceWork priceWork) {
		this.priceWork = priceWork;
	}

	private UpdatePriceWork priceWork;

	

}
